// Andrew Davies

#if !defined( PHYSICS_SHAPE_H )
#define PHYSICS_SHAPE_H

#include "Physics/Shape/physicsShapeFwd.h"
#include "Physics/Feature/physicsFeatureFwd.h"
#pragma warning (disable: 4530)
#include <fuz/container/fixed_vector.hpp>
#pragma warning (default: 4530)
#include "d3d9.h"
#include "Physics/Dynamics/physicsDynamics.h"

namespace Physics
{

#define PHYSICS_SHAPE_MAX_VERTS ( ( int )16 )
	
typedef fuz::fixed_vector< D3DXVECTOR4, PHYSICS_SHAPE_MAX_VERTS > D3DXVECTOR4VectorType;
typedef fuz::fixed_vector< float, PHYSICS_SHAPE_MAX_VERTS > FloatVectorType;

class ShapeClass
{
private:
	int m_UID;

	D3DXVECTOR4VectorType m_vertexPositionVector;  // Made clockwise in constructor.	
	D3DXVECTOR4 m_averageVertexPosition;
	
	D3DXVECTOR4VectorType m_edgeDirectionVector;
	D3DXVECTOR4VectorType m_edgeDirectionUnitVector;
	D3DXVECTOR4VectorType m_edgeNormalDirectionUnitVector;
	FloatVectorType m_edgeLengthVector;

	float m_area;
	float m_mass;	
	bool m_infiniteMass;

	D3DXVECTOR4 m_centerOfMassLocalPosition;

	float m_momentOfInertia;
	
	DynamicsClass m_dynamics;

	D3DXVECTOR4 m_force;
	float m_torque;

public:
	ShapeClass();

	ShapeClass(
		int UID,
		D3DXVECTOR4VectorType const & vertexPositionVector,
		D3DXVECTOR4 const & position,
		float orientation,
		D3DXVECTOR4 const & velocity,
		float angularVelocity,
		D3DXVECTOR4 const & force,
		float torque,
		bool infiniteMass );

	void setDynamics(	
		D3DXVECTOR4 const & position,
		float orientation,
		D3DXVECTOR4 const & velocity,
		float angularVelocity );
	
	void setDynamics( DynamicsClass const & dynamics );

	void stepDynamics( float deltaTime );
	
	//void step(
	//	float deltaTime,
	//	EngineShapeMapType & engineShapeMap );
	
	void draw( IDirect3DDevice9 & d3dDevice ) const;

	int numberOfVertices() const;

	int numberOfEdges() const;
	
	D3DXVECTOR4 vertexPosition( int index ) const;

	D3DXVECTOR4 edgeDirection( int index ) const;

	D3DXVECTOR4 edgeDirectionUnit( int index ) const;

	D3DXVECTOR4 edgeNormalDirectionUnit( int index ) const;

	float edgeLength( int index ) const;
	
	int UID() const
	{
		return m_UID;
	}

	D3DXVECTOR4VectorType const & vertexPositionVector() const
	{
		return m_vertexPositionVector;
	}

	D3DXVECTOR4 const & averageVertexPosition() const
	{
		return m_averageVertexPosition;
	}

	D3DXVECTOR4VectorType const & edgeDirectionVector() const
	{
		return m_edgeDirectionVector;
	}

	D3DXVECTOR4VectorType const & edgeDirectionUnitVector() const
	{
		return m_edgeDirectionUnitVector;
	}

	D3DXVECTOR4VectorType const & edgeNormalDirectionUnitVector() const
	{
		return m_edgeNormalDirectionUnitVector;
	}

	FloatVectorType const & edgeLengthVector() const
	{
		return m_edgeLengthVector;
	}

	float area() const
	{
		return m_area;
	}

	float mass() const
	{
		return m_mass;
	}

	bool infiniteMass() const
	{
		return m_infiniteMass;
	}

	D3DXVECTOR4 const & centerOfMassLocalPosition() const
	{
		return m_centerOfMassLocalPosition;
	}

	float momentOfInertia() const
	{
		return m_momentOfInertia;
	}
	
	DynamicsClass const & dynamics() const 
	{
		return m_dynamics;
	}

	const D3DXVECTOR4& position() const;
	float orientation() const;
	const D3DXVECTOR4& velocity() const;
	float angularVelocity() const;
	const D3DXMATRIX& transformation() const;

	D3DXVECTOR4 const & force() const
	{
		return m_force;
	}

	float torque() const
	{
		return m_torque;
	}	

	void addForceActingAtWorldPosition(
		const D3DXVECTOR4& force,
		const D3DXVECTOR4& worldPosition );

	void setForce( const D3DXVECTOR4& force );
	void clearForce();
	void addForce( const D3DXVECTOR4& force );

	void setTorque( float torque );
	void clearTorque();
	void addTorque( float torque );

	D3DXVECTOR4 transformedAverageVertexPosition() const;

	D3DXVECTOR4 centerOfMassWorldPosition() const;

	D3DXVECTOR4 transformedVertexPosition( int index ) const;

	D3DXVECTOR4 transformedEdgeDirection( int index ) const;

	D3DXVECTOR4 transformedEdgeDirectionUnit( int index ) const;

	D3DXVECTOR4 transformedEdgeNormalDirectionUnit( int index ) const;
};

//ShapeClass * shapeInCollision(	
//	ShapeClass const & shape,
//	EngineShapeMapType & engineShapeMap );

float shapeSignedDistanceFromPlaneToPoint(
	D3DXVECTOR4 const & planePosition,
	D3DXVECTOR4 const & planeUnitNormal,
	D3DXVECTOR4 const & point );

bool shapeBHasSeperatingEdge( ShapeClass const & shapeA, ShapeClass const & shapeB );

bool shapeCollision( ShapeClass const & shapeA, ShapeClass const & shapeB );

void shapeClosestFeatures(
	float & smallestDistanceSquaredSoFar,
	ShapeClass const & shapeA, FeatureClass & shapeAFeature, float & shapeADistanceAlongEdge,
	ShapeClass const & shapeB, FeatureClass & shapeBFeature, float & shapeBDistanceAlongEdge );

bool shapeIntersect(
	ShapeClass const & shape,
	D3DXVECTOR4 const & orig, 
	D3DXVECTOR4 const & dir,
	float & t, float & u, float & v );

D3DXVECTOR4 shapeVelocityAtPoint( ShapeClass const & shape, D3DXVECTOR4 const & pointPosition );
D3DXVECTOR4 shapeVertexVelocity( ShapeClass const & shape, int const vertIdx );


}

#endif